#ifndef __MY_MQ_EXCHANGE_
#define __MY_MQ_EXCHANGE_


#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/helper.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <iostream>
#include <unordered_map>
#include <mutex>

namespace chenmq
{
    //1,定义交换机类--交换机的属性
    class Exchange
    {
    public:
        using ptr = std::shared_ptr<Exchange>;
        std::string name;         //1,交换机名称
        ExchangeType type;         //2,交换机类型, 直接交换，主题交换，广播交换
        bool durable;           //3,持久化标志
        bool auto_delete;       //4,是否自动删除标志
        std::unordered_map<std::string, std::string> args; //其他参数


        Exchange(const std::string& ename, ExchangeType etype, bool edurable,
                 bool eauto_delete, const std::unordered_map<std::string, std::string>& eargs)
                 :name(ename), type(etype), auto_delete(eauto_delete), args(eargs)
        {}

        Exchange()
        {}

        //args存储键值对，在存储到数据库的时候，会组织一个格式字符串进行存储key=val&key=val
        //内部解析这个str_args并存放到args里面
        void setArgs(const std::string& str_args)
        {
            //先用 & 符号将str_args分割得到str， 然后对每个str用 = 号分割就可以得到key, val
            std::vector<std::string> sub_args;
            StrHelper::split(str_args, "&", sub_args);
            for(auto& str: sub_args)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                args[key] = val;
            }
        }

        std::string getArgs() //将args中的内容进行序列化后，返回一个字符串
        {
            std::string result;
            for(auto start = args.begin(); start != args.end(); ++start)
            {
                result += start->first + "=" + start->second + "&";
            }

            return result;
        }
    };

    //名称和交换机智能指针的映射关系
    using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
    //定义交换机数据持久化管理类 因为数据会存储在sqlite数据库中
    class ExchangeMapper
    {
    public:
        ExchangeMapper(const std::string& dbfile)
            :_sql_helper(dbfile)
        {
            //打开sqlite数据库
            std::string path = FileHelper::parentDirectory(dbfile);
            FileHelper::createDirectory(path);
            assert(_sql_helper.open());
            createTable();
        }

        //创建数据库表
        void createTable()
        {
            #define CREATE_TABLE "create table if not exists exchange_table(\
                                  name varchar(32) primary key,\
                                  type int,\
                                  durable int,\
                                  auto_delete int,\
                                  args varchar(128));"
            bool ret = _sql_helper.exec(CREATE_TABLE, nullptr, nullptr);
            if(ret == false)
            {
                ELOG("创建数据库表exchange_table失败");
                abort(); //直接异常退出程序
            }
        }

        void removeTable()
        {
            #define DROP_TABLE "drop table if exists exchange_table;"
            bool ret = _sql_helper.exec(DROP_TABLE, nullptr, nullptr);
            if(ret == false)
            {
                DLOG("删除交换机数据库表失败");
                abort(); 
            }
        }

        //向数据库表插入一个交换机
        bool insert(Exchange::ptr& exp)
        {
            std::stringstream ss;
                ss << "insert into exchange_table values(";
                ss << "'" << exp->name << "', ";
                ss << exp->type << ", ";
                ss << exp->durable << ", ";
                ss << exp->auto_delete << ", ";
                ss << "'" << exp->getArgs() << "');";

            return _sql_helper.exec(ss.str(), nullptr, nullptr);
        }

        // 根据名字从数据库表中移除交换机
        void remove(const std::string& name)
        {
            std::stringstream ss;
            ss << "delete from exchange_table where name=";
            ss << "'" << name << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }

        // Exchange::ptr getOne(const std::string& name);
        // ExchangeMap getAll();

        //从数据库中读出所有的交换机数据并返回
        ExchangeMap recovery()
        {
            ExchangeMap result;
            std::string sql = "select name, type, durable, auto_delete, args from exchange_table;";
            _sql_helper.exec(sql, selectCallback, &result);
            return result;
        }

    private:
        static int selectCallback(void* arg,int numcol,char** row,char** fields) 
        {
            ExchangeMap *result = (ExchangeMap*)arg;
            auto exp = std::make_shared<Exchange>();
            exp->name = row[0];
            exp->type = (chenmq::ExchangeType)std::stoi(row[1]);
            exp->durable = (bool)std::stoi(row[2]);
            exp->auto_delete = (bool)std::stoi(row[3]);
            if (row[4]) exp->setArgs(row[4]);
            result->insert(std::make_pair(exp->name, exp));
            return 0;
        }
    private:
        Sqlitehelper _sql_helper; 
    };


    //定义交换机数据内存管理类--对外使用的
    class ExchangeManager
    {
    public:
        using ptr = std::shared_ptr<ExchangeManager>;
        ExchangeManager(const std::string& dbfile)
            :_mapper(dbfile)
        {
            _exchanges = _mapper.recovery();
        }

        //声明交换机
        void declareExchange(const std::string& name, ExchangeType type, 
            bool durable, bool auto_delete, std::unordered_map<std::string, std::string>& args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if(it != _exchanges.end())
            {
                return;
            }

            auto exp = std::make_shared<Exchange>(name, type, durable, auto_delete, args);
            if(durable == true)
            {
                //所谓的持久化，就是保存一份到sqlite数据库里面
                _mapper.insert(exp);
            }
            _exchanges.insert(std::make_pair(name, exp));
        }

        //删除交换机
        void deleteExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if(it == _exchanges.end())
            {
                return;
            }

            if(it->second->durable == true)
                _mapper.remove(name);
            
            _exchanges.erase(name);
        }

        //获取指定的交换机信息
        Exchange::ptr selectExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if(it == _exchanges.end())
            {
                return Exchange::ptr();
            }

            return it->second;
        }

        //判断交换机是否存在
        bool exists(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if(it == _exchanges.end())
            {
                return false;
            } 
            return true;
        }
        
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchanges.size();
        }

        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _exchanges.clear();
        }

    private:
        std::mutex _mutex;  
        ExchangeMapper _mapper;  //数据库持久化管理类--本质是对sqlite数据库的操作--磁盘中管理(可以持久化)
        ExchangeMap _exchanges; //管理了所有的交换机名称和交换机对象的映射关系--内存中管理
    };

}


#endif